import { jobGoto } from "../../../../job/goto";
import { getMaxEnergy, spawnCreep } from "../../../../role/spawn";
import { errLog } from "../../../../util/log";
import { Group, getCreepNames } from "../../../group";

export class GroupAttacker extends Group{
    constructor(spawnRoom = undefined){
        super(spawnRoom);
        if(spawnRoom !== undefined){
            this.attackerNames = [];
            this.healerNames = [];
            this.spawning = true;
        }
    }

    get attackers(){
        if(this._attackers !== undefined){
            return this._attackers;
        }

        let attackers = [];
        for(let name of this.attackerNames){
            attackers.push(Game.creeps[name]);
        }
        return this._attackers = attackers;
    }
    get healers(){
        if(this._healers !== undefined){
            return this._healers;
        }

        let healers = [];
        for(let name of this.healerNames){
            healers.push(Game.creeps[name]);
        }
        return this._healers = healers;

    }

    serialize(){
        return {
            super: super.serialize(),
            attackerNames: this.attackerNames,
            healerNames: this.healerNames,
            spawning: this.spawning,
        };
    }
    deserialize(obj){
        super.deserialize(obj.super);
        this.spawning = obj.spawning;
        this.attackerNames = getCreepNames(obj.attackerNames);
        this.healerNames = getCreepNames(obj.healerNames);
        return this;
    }
    get size(){
        return this.attackerNames.length+this.healerNames.length;
    }
    get maxSize(){
        if(this.spawning){
            return 4;
        }
        return this.size;
    }
    spawnAttacker(){
        let newCreep = spawnCreep(this.spawnRoom, {
            require: [MOVE,RANGED_ATTACK],
            move: .50,
            ranged_attack: .50,
        },{
            memory: {
                role: "attacker",
            }
        }, getMaxEnergy(this.spawnRoom));
        if(!(newCreep instanceof Creep)){
            return newCreep;
        }
        this.attackerNames.push(newCreep.name);
        return OK;
    }
    spawnHealer(){
        let newCreep = spawnCreep(this.spawnRoom, {
            require: [MOVE,HEAL],
            move: .50,
            heal: .50,
        },{
            memory: {
                role: "healer",
            }
        }, getMaxEnergy(this.spawnRoom));
        if(!(newCreep instanceof Creep)){
            return newCreep;
        }
        this.healerNames.push(newCreep.name);
        return OK;
    }
    spawn(){
        if(!this.spawning){
            return ERR_FULL;
        }
        if(this.healers.length===0){
            return this.spawnHealer();
        }

        if(this.attackers.length<this.healers.length){
            return this.spawnAttacker();
        }

        if(this.healers.length<2){
            return this.spawnHealer();
        }
        return ERR_FULL;
    }
    getDamagedCreeps(){
        if(this._damagedCreeps !== undefined){
            return this._damagedCreeps;
        }

        let targets = this.attackers.filter((target)=>target.hits<target.hitsMax);
        targets.push(...this.healers.filter((target)=>target.hits<target.hitsMax));

        targets.sort((a,b)=>a.hits/a.hitsMax-b.hits/b.hitsMax);

        return this._damagedCreeps = targets;
    }
    run(){
        if(this.spawning){
            for(let creep of this.attackers){
                try{
                    this.renew(creep);
                }catch(e){
                    errLog(e);
                }
            }
            for(let creep of this.healers){
                try{
                    this.renew(creep);
                }catch(e){
                    errLog(e);
                }
            }
            return OK;
        }
        for(let attacker of this.attackers){
            this.attackerRun(attacker);
        }
        for(let i=0; i<this.healers; i++){
            this.healerRun(this.healers[i],i);
        }
    }
    /**
     * 
     * @param {AnyCreep} creep 
     * @returns {CreepActionReturnCode}
     */
    renew(creep){
        if(creep.ticksToLive>1400){
            return OK;
        }
        let spawns = this.spawnRoom.find(FIND_MY_SPAWNS);
        let nearest = jobGoto.getClosest(creep, spawns);
        let ret;
        if(!nearest.pos.isNearTo(creep.pos)){
            ret = jobGoto.run(creep, [nearest]);
        }else{
            ret = nearest.renewCreep(creep);
        }
        creep.say("renew:"+ret);
        return ret;
    }
    /**
     * 
     * @param {AnyCreep} creep 
     */
    attackerRun(creep){
        
    }
    /**
     * 
     * @param {AnyCreep} creep 
     */
    healerRun(creep){
        let targets = this.getDamagedCreeps();
        let near = false;
        for(let target of this.attackers){
            if(creep.pos.isNearTo(target.pos)){
                near = true;
                break;
            }
        }
    }
}